﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;

namespace CompilerForC.SyntaxAnalysis.TreeCollection
{
    /// <summary>
    /// Collection of read-only tree nodes.
    /// </summary>
    /// <typeparam name="T">Type of the TreeNode class generic parameter.</typeparam>
    public class TreeNodeCollection<T> : ReadOnlyCollection<TreeNode<T>>
    {
        #region Constructor

        /// <summary>
        /// Constructs TreeNodeCollection from specified list of nodes.
        /// </summary>
        /// <param name="treeNodes">List of tree nodes.</param>
        public TreeNodeCollection(IList<TreeNode<T>> treeNodes) : base(treeNodes)
        {
        }

        #endregion Constructor
    }

    /// <summary>
    /// Encapsulates single node in the generic tree.
    /// </summary>
    /// <typeparam name="T">Type of the node's value.</typeparam>
    public class TreeNode<T>
    {
        #region Private Fields

        /// <summary>
        /// Value contained within node.
        /// </summary>
        private T _value;
        /// <summary>
        /// Parent node reference.
        /// </summary>
        private TreeNode<T> _parent;
        /// <summary>
        /// Child node list.
        /// </summary>
        private List<TreeNode<T>> _children = new List<TreeNode<T>>();

        #endregion Private Fields

        #region Public Properties

        /// <summary>
        /// Gets or sets value contained within node.
        /// </summary>
        public T Value
        {
            get { return _value; }
            set { _value = value; }
        }

        /// <summary>
        /// Gets or sets parent of the node. Can be null. Node is removed from 
        /// previous parent's (if any) child node list.
        /// </summary>
        public TreeNode<T> Parent
        {
            get { return _parent; }
            set
            {
                if (_parent != null)
                    _parent._children.Remove(this);

                _parent = value;

                if (_parent != null)
                    _parent._children.Add(this);
            }
        }

        /// <summary>
        /// Gets read-only child node collection.
        /// </summary>
        public TreeNodeCollection<T> Children
        {
            get { return new TreeNodeCollection<T>(_children); }
        }

        #endregion Public Properties

        #region Contructors

        /// <summary>
        /// Constructs TreeNode with default value.
        /// Initially, node does not have parent nor child nodes.
        /// </summary>
        public TreeNode() : this(null, default(T))
        {
        }

        /// <summary>
        /// Constructs TreeNode from specified value.
        /// Initially, node does not have parent nor child nodes.
        /// </summary>
        /// <param name="value">Initial value contained within node.</param>
        public TreeNode(T value) : this(null, value)
        {
        }

        /// <summary>
        /// Constructs TreeNode as child node of the specified parent. Node has
        /// default value.
        /// </summary>
        /// <param name="parent">Parent node.</param>
        public TreeNode(TreeNode<T> parent) : this(parent, default(T))
        {
        }

        /// <summary>
        /// Constructs TreeNode as child node of the specified parent. Node's
        /// value is assigned with specified value.
        /// </summary>
        /// <param name="parent">Parent node.</param>
        /// <param name="value">Initial value contained within node.</param>
        public TreeNode(TreeNode<T> parent, T value)
        {
            Parent = parent;
            _value = value;
        }

        #endregion Contructors

        #region Public Methods

        /// <summary>
        /// Adds new child node of specified value.
        /// </summary>
        /// <param name="value">Value that will be contained within new 
        /// child node.</param>
        /// <returns>Added child node.</returns>
        public TreeNode<T> Add(T value)
        {
            return Add(new TreeNode<T>(value));
        }

        /// <summary>
        /// Adds new child node.
        /// </summary>
        /// <param name="node">Child node to add.</param>
        /// <returns>Added child node.</returns>
        public TreeNode<T> Add(TreeNode<T> node)
        {
            node.Parent = this;
            return node;
        }

        #endregion Public Methods

        #region Object Members

        /// <summary>
        /// Converts node's value to string.
        /// </summary>
        /// <returns>String representation of the node's value.</returns>
        public override string ToString()
        {
            return _value.ToString();
        }

        #endregion Object Members
    }
}
